<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>xeokit Example</title>
    <link href="../css/pageStyle.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
    <style>
        #storeys {
            overflow: hidden;
            background-color: white;
            position: absolute;
            left: 10px;
            bottom: 10px;
            width: 400px;
            height: 409px;
            /* margin-top: 20px; */
            opacity: 0.8 !important;
            border-radius: 15px;

            /* margin-bottom: 10px; */
            pointer-events: all;
            opacity: 1.0;

            display: none;
        }

        .marker {
            position: absolute;
            width: 15px;
            height: 15px;
            background-color: red;
            border-radius: 50%;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 1000;
        }

        .dropdown {
            position: absolute;
            top: 10px;
            width: 95%;
            height: 35px;
            left: 50%;
            transform: translateX(-50%);
            background-color: black;
            border-radius: 5px;
            display: flex;
            flex-direction: row;
            justify-content: flex-start;
            align-items: center;
            align-content: center;
            z-index: 1000;
        }

        .dropdown.opened {
            border-bottom-left-radius: 0px;
            border-bottom-right-radius: 0px;
        }

        .dropdown.closed {
            border-bottom-left-radius: 5px;
            border-bottom-right-radius: 5px;
        }

        .dropdown:hover {
            cursor: pointer;
        }

        .hamburger {
            color: white;
            font-size: 20px;
            margin-left: 20px;
        }

        .floor {
            color: white;
            font-size: 16px;
            margin-left: 10px;
        }

        .dropdown-options {
            position: absolute;
            top: 45px;
            width: 95%;
            height: auto;
            left: 50%;
            transform: translateX(-50%);
            background-color: black;
            /* border-radius: 5px; */
            display: none;
            flex-direction: column;
            justify-content: flex-start;
            z-index: 1000;
        }

        .option {
            border-top: 1px solid white;
            width: 100%;
            height: 35px;
            color: white;
            display: flex;
            flex-direction: row;
            justify-content: flex-start;
            align-items: center;
            align-content: center;
        }

        .option:hover {
            cursor: pointer;
        }

        .option .check {
            color: black;
            font-size: 20px;
            margin-left: 20px;
        }

        .option.selected .check {
            color: lightgreen;
        }

        .option .floor-number {
            color: white;
            font-size: 16px;
            margin-left: 10px;
        }
    </style>
</head>

<body>
    <input type="checkbox" id="info-button" />
    <label for="info-button" class="info-button"><i class="far fa-3x fa-question-circle"></i></label>
    <canvas id="myCanvas"></canvas>
    <div id="storeys">
        <div class="dropdown closed" id="dropdown">
            <label for="hamburger" class="hamburger"><i class="fas fa-bars"></i></label>
            <span class="floor" id="selected-floor">3rd Floor</span>
        </div>
        <div class="dropdown-options" id="dropdown-options">
        </div>
        <div class="marker" id="marker"></div>
    </div>
    <div class="slideout-sidebar">
        <img class="info-icon" src="../../assets/images/storey_views_icon.png" />
        <h1>StoreyViewsPlugin</h1>
        <h2>Minimap</h2>
        <p>Click a room in the plan images to go there in <b>first-person mode</b>. </p>
        <h3>Components Used</h3>
        <ul>
            <li>
                <a href="../../docs/class/src/viewer/Viewer.js~Viewer.html" target="_other">Viewer</a>
            </li>
            <li>
                <a href="../../docs/class/src/plugins/StoreyViewsPlugin/StoreyViewsPlugin.js~StoreyViewsPlugin.html"
                    target="_other">StoreyViewsPlugin</a>
            </li>
            <li>
                <a href="../../docs/class/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js~XKTLoaderPlugin.html"
                    target="_other">XKTLoaderPlugin</a>
            </li>
            <li>
                <a href="../../docs/class/src/viewer/scene/camera/CameraFlightAnimation.js~CameraFlightAnimation.html"
                    target="_other">CameraFlightAnimation</a>
            </li>
        </ul>
        <h3>Resources</h3>
        <ul>
            <li>
                <a href="https://github.com/openBIMstandards/DataSetSchependomlaan" target="_other">Model source</a>
            </li>
        </ul>
    </div>
</body>

<script type="module">
    //------------------------------------------------------------------------------------------------------------------
    // Import the modules we need for this example
    //------------------------------------------------------------------------------------------------------------------

    import { Viewer, StoreyViewsPlugin, math, XKTLoaderPlugin, CameraMemento } from "../../dist/xeokit-sdk.es.js";

    //------------------------------------------------------------------------------------------------------------------
    // Helping Variables
    //------------------------------------------------------------------------------------------------------------------

    let selectedStoreyId = '';

    //------------------------------------------------------------------------------------------------------------------
    // Create a Viewer, arrange the camera
    //------------------------------------------------------------------------------------------------------------------

    const viewer = new Viewer({
        canvasId: "myCanvas",
        transparent: true,
        edges: true
    });

    viewer.camera.eye = [-2.56, 8.38, 8.27];
    viewer.camera.look = [13.44, 3.31, -14.83];
    viewer.camera.up = [0.10, 0.98, -0.14];

    viewer.camera.project.fovy = 70;

    //------------------------------------------------------------------------------------------------------------------
    // Load a model
    //------------------------------------------------------------------------------------------------------------------

    const xktLoader = new XKTLoaderPlugin(viewer);

    const sceneModel = xktLoader.load({
        id: "myModel",
        src: "../../assets/models/xkt/v11/ifc/Duplex/Duplex_A.xkt",
        edges: true,
        objectDefaults: { // This model has opaque windows / spaces; make them transparent
            "IfcPlate": {
                opacity: 0.3 // These are used as windows in this model - make transparent
            },
            "IfcWindow": {
                opacity: 0.4
            },
            "IfcSpace": {
                opacity: 0.4
            }
        }
    });

    //------------------------------------------------------------------------------------------------------------------
    // Add a StoreyViewsPlugin
    //------------------------------------------------------------------------------------------------------------------

    const storeyViewsPlugin = new StoreyViewsPlugin(viewer);
    const allStoreyMaps = [];

    //------------------------------------------------------------------------------------------------------------------
    // When model loaded, build a clickable set of storey plan images from the StoreyViewsPlugin, bind mouse
    // events to fly the Camera to a first-person view at whatever location we click within each plan view image
    //------------------------------------------------------------------------------------------------------------------

    sceneModel.on("loaded", function () {

        viewer.cameraFlight.jumpTo(sceneModel);

        // Make all doors transparent
        viewer.scene.setObjectsOpacity(viewer.metaScene.getObjectIDsByType("IfcDoor"), 0.3);

        buildStoreyMapsMenu();
    });

    function buildStoreyMapsMenu() {

        const cameraMemento = new CameraMemento(); // Saves 3D perspective camera to restore
        cameraMemento.saveCamera(viewer.scene);

        const storeyDiv = document.getElementById("storeys");
        const optionsDiv = document.getElementById("dropdown-options");

        const storeys = storeyViewsPlugin.storeysList;

        for (let i = 0, len = storeys.length; i < len; i++) {

            const storey = storeys[i];
            const storeyId = storey.storeyId;

            const storeyMap = storeyViewsPlugin.createStoreyMap(storeyId, {
                format: "png",
                width: 400
            });

            allStoreyMaps.push(storeyMap);

            const img = document.createElement("img");
            img.className = 'storeyMap';
            img.src = storeyMap.imageData;
            img.id = `${storeyId}`;
            img.style.borderRadius = "15px";
            img.style.background = "lightblue";
            img.style.width = "100%";
            img.style.height = "100%";
            img.style.opacity = 0.8;
            img.style.display = 'none';

            storeyDiv.appendChild(img);

            const option = document.createElement('div');
            option.className = 'option';
            option.innerHTML = `
                <label for="check" class="check"><i class="fas fa-check"></i></label>
                <span class="floor-number">${getOrdinalSuffix(i + 1)} Floor</span>
            `;
            option.id = `option${i + 1}`;

            optionsDiv.appendChild(option);

            img.onmouseenter = () => {
                img.style.cursor = "default";
            };

            img.onmousemove = (e) => {
                img.style.cursor = "default";
                const imagePos = [e.offsetX, e.offsetY];
                const pickResult = storeyViewsPlugin.pickStoreyMap(storeyMap, imagePos, {});
                if (pickResult) {
                    const entity = pickResult.entity;
                    const metaObject = viewer.metaScene.metaObjects[entity.id];
                    if (metaObject) {
                        img.style.cursor = "pointer";
                    }
                }
            };

            img.onmouseleave = (e) => {
                img.style.cursor = "default";
            };

            const worldPos = math.vec3();

            img.onclick = (e) => {
                //forcefully close the dropdown
                toggleDropdown(true);
                const imagePos = [e.offsetX, e.offsetY];

                const pickResult = storeyViewsPlugin.pickStoreyMap(storeyMap, imagePos, {
                    pickSurface: true
                });

                if (pickResult) {

                    worldPos.set(pickResult.worldPos);

                    // Set camera vertical position at the mid point of the storey's vertical
                    // extents - note how this is adapts to whichever of the X, Y or Z axis is
                    // designated the World's "up" axis

                    const camera = viewer.scene.camera;
                    const idx = camera.xUp ? 0 : (camera.yUp ? 1 : 2); // Find the right axis for "up"
                    const storey = storeyViewsPlugin.storeys[storeyMap.storeyId];
                    worldPos[idx] = (storey.aabb[idx] + storey.aabb[3 + idx]) / 2;
                    viewer.cameraFlight.flyTo({
                        eye: worldPos,
                        up: viewer.camera.worldUp,
                        look: math.addVec3(worldPos, viewer.camera.worldForward, []),
                        projection: "perspective",
                        duration: 1.5
                    }, () => {
                        getStorey()
                        viewer.cameraControl.navMode = "firstPerson";
                    });
                }
            };
        }

        viewer.camera.on('viewMatrix', function () {
            getStorey();
        })

        document.getElementById("storeys").style.display = "block";
        document.getElementById("dropdown").addEventListener('click', onDropdownClicked);
        document.querySelectorAll('.option').forEach((el, index) => {
            el.addEventListener('click', (e) => {
                onOptionSelected(e, index + 1);
            })
        })
    }

    const marker = document.getElementById("marker");

    function getStorey() {
        const cameraPos = viewer.camera.eye;
        let storeyId = getStoreyId(cameraPos);
        setFloorDropdown(storeyId);
        hideStoreyMaps();
        const el = document.getElementById(`${storeyId}`)
        el.style.display = "block";
        const cameraDir = viewer.camera.worldForward;
        const storeyMap = allStoreyMaps.filter(storey => storey.storeyId === storeyId)[0];
        const imageDir = math.vec2(), imagePos = math.vec2();
        storeyViewsPlugin.worldDirToStoreyMap(storeyMap, cameraDir, imageDir);
        storeyViewsPlugin.worldPosToStoreyMap(storeyMap, cameraPos, imagePos);
        const centerX = 400 / 2;
        const centerY = 400 / 2;
        const angle = calculateAngleFromDirection(imageDir);
        const transformedPosition = transformCoordinates(imagePos[0], imagePos[1], -angle, centerX, centerY);
        const translateX = centerX - transformedPosition.x;
        const translateY = centerY - transformedPosition.y;
        el.style.transform = `translate(${translateX}px, ${translateY}px) rotate(${angle}deg)`;
    }

    function getStoreyId(cameraPos) {
        let storey = null;
        storey = storeyViewsPlugin.getStoreyContainingWorldPos(cameraPos);
        if (storey === null) {
            storey = storeyViewsPlugin.getStoreyInVerticalRange(cameraPos);
            if (storey === null) {
                storey = storeyViewsPlugin.isPositionAboveOrBelowBuilding(cameraPos);
            }
        }
        return storey;
    }

    //------------------------------------------------------------------------------------------------------------------
    // Dropdown UI
    //------------------------------------------------------------------------------------------------------------------

    function setFloorDropdown(storeyId) {
        if (storeyId === selectedStoreyId) return;
        selectedStoreyId = storeyId;
        let floor = 0;
        for (let i = 0; i < allStoreyMaps.length; i++) {
            if (storeyId === allStoreyMaps[i].storeyId) {
                floor = i + 1;
                break;
            }
        }

        selectOption(floor);
    }

    function onDropdownClicked(e) {
        const dropdown = document.getElementById("dropdown");

        toggleDropdown(dropdown.classList.contains('opened'));
    }


    //takes a paramter describing whether the dropdown is currently visible or not
    function toggleDropdown(visible) {
        if (visible) {
            dropdown.classList.remove('opened');
            dropdown.classList.add('closed');
            document.getElementById("dropdown-options").style.display = "none";
        }
        else {
            dropdown.classList.remove('closed');
            dropdown.classList.add('opened');
            document.getElementById("dropdown-options").style.display = "flex";
        }
    }

    function onOptionSelected(e, floor) {
        selectOption(floor);
        toggleDropdown(true);
        const storeyId = allStoreyMaps[floor - 1].storeyId;
        const storey = storeyViewsPlugin.storeys[storeyId];
        const worldPos = [
            (storey.aabb[0] + storey.aabb[3]) / 2,
            (storey.aabb[1] + storey.aabb[4]) / 2,
            (storey.aabb[2] + storey.aabb[5]) / 2
        ]
        viewer.cameraFlight.flyTo({
            eye: worldPos,
            up: viewer.camera.worldUp,
            look: math.addVec3(worldPos, viewer.camera.worldForward, []),
            projection: "perspective",
            duration: 1.5
        }, () => {
            getStorey()
            viewer.cameraControl.navMode = "firstPerson";
        });
    }

    //------------------------------------------------------------------------------------------------------------------
    // Utility functions
    //------------------------------------------------------------------------------------------------------------------

    function radToDeg(rad) {
        return rad * (180 / Math.PI);
    }

    function getOrdinalSuffix(number) {
        const suffixes = ["th", "st", "nd", "rd"];
        const v = number % 100;
        return number + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);
    }

    function hideStoreyMaps() {
        const elements = document.querySelectorAll('.storeyMap');
        elements.forEach(element => {
            element.style.display = 'none';
        });
    }

    function unSelectAllOptions() {
        const optionElements = document.querySelectorAll(".option");
        optionElements.forEach(el => {
            el.classList.remove('selected');
        })
    }

    function selectOption(floor) {
        unSelectAllOptions();
        document.getElementById("selected-floor").innerHTML = `${getOrdinalSuffix(floor)} Floor`;
        document.getElementById(`option${floor}`).classList.add('selected');
    }

    function calculateAngleFromDirection(direction) {
        const angleInRad = Math.atan2(direction[0], direction[1]);
        const angleInDeg = angleInRad * (180 / Math.PI);
        return angleInDeg;
    }

    // Function to rotate a point around the origin (0, 0)
    function rotatePoint(x, y, angle) {
        const radians = angle * Math.PI / 180;
        const cos = Math.cos(radians);
        const sin = Math.sin(radians);
        return {
            x: cos * x - sin * y,
            y: sin * x + cos * y
        };
    }

    // Function to transform coordinates based on image rotation
    function transformCoordinates(x, y, angle, centerX, centerY) {
        // Translate point to origin
        const translatedX = x - centerX;
        const translatedY = y - centerY;

        // Rotate the point
        const rotatedPoint = rotatePoint(translatedX, translatedY, -angle);

        // Translate the point back
        const finalX = rotatedPoint.x + centerX;
        const finalY = rotatedPoint.y + centerY;

        return { x: finalX, y: finalY };
    }

</script>